package Redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.params.SetParams;

import java.util.ArrayList;
import java.util.List;

public class Rdo {
    // 常量定义
    private static final int LOCK_TIMEOUT = 10;
    private static final String OBSTACLE_KEY = "map:obstacle";
    private static final String CAR_POSITION_FORMAT = "car:%s:position";
    private static final String TASK_QUEUE_FORMAT = "car:%s:tasks";
    private static final String LOCK_KEY_FORMAT = "lock:area:%d:%d";
    private static final String LIGHT_KEY = "map:light";
    private static final String CAR_COUNT_KEY = "carcount";

    private Jedis jedis;

    // 连接方法
    public void connect(String host, int port) {
        try {
            jedis = new Jedis(host, port);
            System.out.println("✅ Redis连接成功");
            System.out.println("Ping响应: " + jedis.ping());
        } catch (Exception e) {
            logError("Redis连接失败", e);
        }
    }

    // 核心移动逻辑
    public void move(String carId, String time) {
        initCarPathIfEmpty(carId, Double.parseDouble(time));
        String aim = getdestion(carId);
        if (aim == null) return;
        Position nextPos = parsePosition(aim);
        if (nextPos == null) return;
        Position oldPos = loadCarPosition(carId);
        if (oldPos != null && isSamePosition(oldPos, nextPos)) {
            return;
        }
        if (earlyObstacleCheck(carId, nextPos.x, nextPos.y)) {
            return;
        }
        if (getresult(carId)) {
            clearTasks(carId);
            return;
        }
        String lockKey = String.format(LOCK_KEY_FORMAT, nextPos.x, nextPos.y);
        try {
            if (!acquireLock(lockKey, carId)) {
                clearTasks(carId);
                return;
            }
            if (postLockObstacleCheck(carId, nextPos.x, nextPos.y)) {
                return;
            }
            updateSystemStateWithTransaction(carId, nextPos, oldPos, time);
            light(carId, nextPos.x, nextPos.y);
        } finally {
            releaseLock(lockKey, carId);
        }
    }

    // 使用事务更新系统状态
    private void updateSystemStateWithTransaction(String carId, Position newPos, Position oldPos, String timeStr) {
        try {

            Transaction t = jedis.multi();
            // 更新车辆位置
            String positionKey = String.format(CAR_POSITION_FORMAT, carId);
            t.hset(positionKey, "x", String.valueOf(newPos.x));
            t.hset(positionKey, "y", String.valueOf(newPos.y));
            // 记录路径
            t.zadd("car:" + carId + ":path", Double.parseDouble(timeStr), newPos.toString());
            // 执行事务
            t.exec();
        } catch (Exception e) {
            logError("事务更新异常", e);
        }
    }

    // 解析坐标字符串
    private Position parsePosition(String coordStr) {
        try {
            String[] parts = coordStr.split(" ");
            if (parts.length < 2) return null;
            int x = Integer.parseInt(parts[0]);
            int y = Integer.parseInt(parts[1]);
            return new Position(x, y);
        } catch (NumberFormatException | NullPointerException e) {
            return null;
        }
    }

    // 获取车辆当前位置
    private Position loadCarPosition(String carId) {
        String key = String.format(CAR_POSITION_FORMAT, carId);
        String xStr = jedis.hget(key, "x");
        String yStr = jedis.hget(key, "y");

        if (xStr == null || yStr == null) return null;

        try {
            int x = Integer.parseInt(xStr);
            int y = Integer.parseInt(yStr);
            return new Position(x, y);
        } catch (NumberFormatException e) {
            logError("位置数据异常: " + carId, e);
            return null;
        }
    }

    // 判断是否是同一位置
    private boolean isSamePosition(Position a, Position b) {
        return a != null && b != null && a.x == b.x && a.y == b.y;
    }

    // 修改障碍检查逻辑（替换原checkObstacle调用）
    private boolean earlyObstacleCheck(String carId, int x, int y) {
        if (isPositionOccupied(x, y)) { // 优先检查小车占用
            clearTasks(carId);
            return true;
        }
        if (checkStaticObstacle(x, y)) { // 再检查静态障碍
            clearTasks(carId);
            return true;
        }
        return false;
    }
    // 拆分静态障碍检查（新增方法）
    private boolean checkStaticObstacle(int x, int y) {
        int mapWidth = getMapWidth();
        long index = (long) y * mapWidth + x;
        return jedis.getbit(OBSTACLE_KEY, index); // 仅检查原始障碍物
    }
    // 加锁后二次检查
    private boolean postLockObstacleCheck(String carId, int x, int y) {
        if (checkObstacle(x, y)) {
            clearTasks(carId);
            return true;
        }
        return false;
    }

    // 获取分布式锁
    private boolean acquireLock(String lockKey, String carId) {
        String result = jedis.set(lockKey, carId,
                SetParams.setParams().nx().ex(LOCK_TIMEOUT));

        if (!"OK".equals(result)) {
            logInfo("资源锁定失败: " + lockKey);
            clearTasks(carId);
            return false;
        }
        return true;
    }

    // 释放锁
    private void releaseLock(String lockKey, String carId) {
        try {
            String script =
                    "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                            "   return redis.call('del', KEYS[1]) " +
                            "else return 0 end";
            jedis.eval(script, 1, lockKey, carId);
        } catch (Exception e) {
            logError("锁释放异常", e);
        }
    }

    // 障碍物检查
    private boolean checkObstacle(int x, int y) {
        int mapWidth = getMapWidth();
        long index = (long) y * mapWidth + x;
        return jedis.getbit(OBSTACLE_KEY, index);
    }

    // 清空任务队列
    private void clearTasks(String carId) {
        String taskKey = String.format(TASK_QUEUE_FORMAT, carId);
        jedis.del(taskKey);
    }

    // 日志方法
    private void logInfo(String message) {
        System.out.println("[INFO] " + message);
    }

    private void logError(String message, Exception e) {
        System.err.println("[ERROR] " + message + ": " + e.getMessage());
    }

    // 获取地图宽度
    public int getMapWidth() {
        String width = jedis.get("mapwidth");
        return width == null ? 0 : Integer.parseInt(width);
    }

    // 获取地图高度
    public int getMapHeight() {
        String height = jedis.get("mapheight");
        return height == null ? 0 : Integer.parseInt(height);
    }

    // 关闭连接
    public void close() {
        if (jedis != null) {
            jedis.close();
            System.out.println("🔌 连接已关闭");
        }
    }

    // 点亮小车周围区域
//    public void light(String carId, int centerX, int centerY) {
//        try {
//            int mapWidth = getMapWidth();
//            int mapHeight = getMapHeight();
//
//            for (int dx = -1; dx <= 1; dx++) {
//                for (int dy = -1; dy <= 1; dy++) {
//                    int x = centerX + dx;
//                    int y = centerY + dy;
//                    if (x >= 0 && x < mapWidth && y >= 0 && y < mapHeight) {
//                        long index = (long) y * mapWidth + x;
//                        jedis.setbit(LIGHT_KEY, index, true);
//                    }
//                }
//            }
//        } catch (Exception e) {
//            logError("点亮失败", e);
//        }
//    }
    public void light(String carId, int centerX, int centerY) {
        try {
            int mapWidth = getMapWidth();
            int mapHeight = getMapHeight();

            for (int dx = -1; dx <= 1; dx++) {
                for (int dy = -1; dy <= 1; dy++) {
                    int x = centerX + dx;
                    int y = centerY + dy;
                    if (x >= 0 && x < mapWidth && y >= 0 && y < mapHeight) {
                        long index = (long) y * mapWidth + x;
                        jedis.setbit(LIGHT_KEY, index, true);
                    }
                }
            }
        } catch (Exception e) {
            logError("点亮失败", e);
        }
    }
    // 获取任务坐标
    public String getdestion(String id) {
        String key = String.format(TASK_QUEUE_FORMAT, id);
        String result = jedis.rpop(key);
        System.out.println("🎯 从任务队列获取到目标点: " + (result != null ? result : "空"));
        return result;
    }

    // 检查最后一个任务是否被点亮
    public boolean getresult(String id) {
        String key = String.format(TASK_QUEUE_FORMAT, id);
        String lastCoordinate = jedis.lindex(key, 0);
        if (lastCoordinate == null) return false;

        Position pos = parsePosition(lastCoordinate);
        if (pos == null) return false;

        int mapWidth = getMapWidth();
        long index = (long) pos.y * mapWidth + pos.x;
        boolean hasLight = jedis.getbit(LIGHT_KEY, index);

        System.out.println("小车终点坐标：x:" + pos.x + ",y:" + pos.y + " 状态：" + (hasLight ? "有光" : "无光"));
        return hasLight;
    }

    // 坐标结构体
    private static class Position {
        int x, y;

        Position(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public String toString() {
            return x + " " + y;
        }
    }

    // 初始化车辆路径
    public void initCarPathIfEmpty(String carId, double time) {
        String pathKey = "car:" + carId + ":path";
        if (jedis.zcard(pathKey) == 0) {
            Position initialPos = loadCarPosition(carId);
            if (initialPos != null) {
                double timestamp = time - 1;
                jedis.zadd(pathKey, timestamp, initialPos.toString());
                logInfo("✅ initalposition: " + initialPos + " @time：" + timestamp);
            }
        }
    }

    // 获取目标车辆数量
    public int getTargetCarCount() {
        return jedis.exists(CAR_COUNT_KEY) ? Integer.parseInt(jedis.get(CAR_COUNT_KEY)) : 0;
    }

    // 新增方法：检查目标位置是否被其他小车占用
    public boolean isPositionOccupied(int x, int y) {
        int count=getTargetCarCount();
        for (int i=1;i<=count;i++) {
            Position pos = loadCarPosition(String.valueOf(i));
            if (pos != null && pos.x == x && pos.y == y) {
                return true;
            }
        }
        return false;
    }
}
